package com.uminho.calendar;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.util.MonthDisplayHelper;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;

import com.uminho.egendme.R;

/****c* Calendar/CalendarView
 * DESCRIPTION
 * Classe responsável pela vista do Calendário
 *
 ****
 */

public class CalendarView extends ImageView{
	Handler messages=null;
	Paint old=null;
	public boolean swipedNext=false, swipePrev=false;;
	private HashMap<Date, Integer> busyDays=null;
    private static int WEEK_TOP_MARGIN = 0;
    private static int WEEK_LEFT_MARGIN = 0;
    private static int CELL_WIDTH = 103;
    private static int CELL_HEIGH = 170;
    private static int CELL_MARGIN_TOP = 20;
    private static int CELL_MARGIN_LEFT = 0;
    private static float CELL_TEXT_SIZE=30;
   
	/*private static final String TAG = "CalendarView"; */
	private Calendar mRightNow = null;
    private Drawable mWeekTitle = null;
    private Cell mToday = null;
    private Cell[][] mCells = new Cell[6][7];
    private OnCellTouchListener mOnCellTouchListener = null;
    MonthDisplayHelper mHelper;
    Drawable mDecoration = null;
    private Context context=null;


    
    private GestureDetector gestureDetector;

    
	public interface OnCellTouchListener {
    	public void onTouch(Cell cell);
    }

	public CalendarView(Context context) {
		this(context, null);
	}
	
	public CalendarView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public CalendarView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		this.context=context;
		mDecoration = context.getResources().getDrawable(R.drawable.typeb_calendar_today);	
  		//init gesture detector
  		gestureDetector = new GestureDetector(new MyGestureDetector());
  		messages = new Handler() {

			@Override
			public void handleMessage(Message msg) {
				Log.d("CaldarView message", ""+msg.what);
				
				
			}
		};
  		initCalendarView();
	}
	
	/****f* CalendarView/initCalendarView
	 * DESCRIPTION
	 * Método executado para inicializar a vista do calendário
	 * RESULT
	 * Vista iniciada
	 *
	 ****
	 */
	private void initCalendarView() {
		mRightNow = Calendar.getInstance();
		
		// prepare static vars
		Resources res = getResources();
		
		WEEK_TOP_MARGIN  = (int) res.getDimension(R.dimen.week_top_margin);
		WEEK_LEFT_MARGIN = (int) res.getDimension(R.dimen.week_left_margin);
		CELL_WIDTH = (int) res.getDimension(R.dimen.cell_width);
		CELL_HEIGH = (int) res.getDimension(R.dimen.cell_heigh);
		CELL_MARGIN_TOP = (int) res.getDimension(R.dimen.cell_margin_top);
		CELL_MARGIN_LEFT = (int) res.getDimension(R.dimen.cell_margin_left);
		CELL_TEXT_SIZE = res.getDimension(R.dimen.cell_text_size);
		
		this.setImageResource(android.R.color.transparent);
		
		mWeekTitle = res.getDrawable(R.drawable.calendar_week3);
		mHelper = new MonthDisplayHelper(mRightNow.get(Calendar.YEAR), mRightNow.get(Calendar.MONTH));
}
	
	/****f* CalendarView/initCells
	 * DESCRIPTION
	 * Método executado para inicializar os valores de cada célula do calendário
	 * RESULT
	 * Celulas iniciada
	 *
	 ****
	 */
	private void initCells() {
		//init disponibilidades
		if(busyDays==null) busyDays = new HashMap<Date,Integer>();
		
	    class _calendar {
	    	public int day;
	    	public boolean thisMonth;
	    	public _calendar(int d, boolean b) {
	    		day = d;
	    		thisMonth = b;
	    	}
	    	public _calendar(int d) {
	    		this(d, false);
	    	}
	    };
	    _calendar tmp[][] = new _calendar[6][7];
	    
	    for(int i=0; i<tmp.length; i++) {
	    	int n[] = mHelper.getDigitsForRow(i);
	    	for(int d=0; d<n.length; d++) {
	    		if(mHelper.isWithinCurrentMonth(i,d))
	    			tmp[i][d] = new _calendar(n[d], true);
	    		else
	    			tmp[i][d] = new _calendar(n[d]);
	    		
	    	}
	    }

	    Calendar today = Calendar.getInstance();
	    int thisDay = 0;
	    mToday = null;
	    if(mHelper.getYear()==today.get(Calendar.YEAR) && mHelper.getMonth()==today.get(Calendar.MONTH)) {
	    	thisDay = today.get(Calendar.DAY_OF_MONTH);
	    }
		// build cells
		Rect Bound = new Rect(CELL_MARGIN_LEFT, CELL_MARGIN_TOP, CELL_WIDTH+CELL_MARGIN_LEFT, CELL_HEIGH+CELL_MARGIN_TOP);
		for(int week=0; week<mCells.length; week++) {
			for(int day=0; day<mCells[week].length; day++) {
				
				boolean isToday = false;
				if(tmp[week][day].day==thisDay && tmp[week][day].thisMonth) {
					isToday = true;
				}
				
				if(tmp[week][day].thisMonth) {
					if(day==0 || day==6 )
						mCells[week][day] = new RedCell(tmp[week][day].day, new Rect(Bound), CELL_TEXT_SIZE, this.context, busyDays, getMonth() ,getYear(),isToday);
					else 
						mCells[week][day] = new Cell(tmp[week][day].day, new Rect(Bound), CELL_TEXT_SIZE, this.context, busyDays, getMonth() ,getYear(),isToday);
				
				} else
					mCells[week][day] = new GrayCell(tmp[week][day].day, new Rect(Bound), CELL_TEXT_SIZE, this.context, busyDays, getMonth() ,getYear(), isToday);
				
				Bound.offset(CELL_WIDTH, 0); // move to next column 
				
				// get today
				if(tmp[week][day].day==thisDay && tmp[week][day].thisMonth) {
					mToday = mCells[week][day];
					mDecoration.setBounds(mToday.getBound());
				}
			}
			Bound.offset(0, CELL_HEIGH); // move to next row and first column
			Bound.left = CELL_MARGIN_LEFT;
			Bound.right = CELL_MARGIN_LEFT+CELL_WIDTH;
		}		
	}
	
	@Override
	public void onLayout(boolean changed, int left, int top, int right, int bottom) {
		Rect re = getDrawable().getBounds();
		WEEK_LEFT_MARGIN = CELL_MARGIN_LEFT = (right-left - re.width()) / 2;
		mWeekTitle.setBounds(WEEK_LEFT_MARGIN, WEEK_TOP_MARGIN, this.getWidth(), WEEK_TOP_MARGIN+mWeekTitle.getMinimumHeight());
		initCells();
		super.onLayout(changed, left, top, right, bottom);
	}
	
    public void setTimeInMillis(long milliseconds) {
    	mRightNow.setTimeInMillis(milliseconds);
    	initCells();
    	this.invalidate();
    }
       
    public int getYear() {
    	return mHelper.getYear();
    }
    
    public int getMonth() {
    	return mHelper.getMonth();
    }
    public void addValueMonth() {
    	
    	initCells();
    	invalidate();
    }
    
    /****f* CalendarView/nextMonth
	 * DESCRIPTION
	 * Método executado para delizar para o próximo mês
	 * RESULT
	 * Mês seguinte é mostrado
	 *
	 ****
	 */ 
    public void nextMonth() {
    	Animation slide = AnimationUtils.loadAnimation(context, R.anim.slide_right);
        findViewById(R.id.calendar).startAnimation(slide);
    	
    	mHelper.nextMonth();
    	initCells();
    	invalidate();
    }
    
    /****f* CalendarView/previousMonth
	 * DESCRIPTION
	 * Método executado para delizar para o mês anterior
	 * RESULT
	 * Mês anterior é mostrado
	 *
	 ****
	 */ 
    public void previousMonth() {
    	Animation slide = AnimationUtils.loadAnimation(context, R.anim.slide_left);
        findViewById(R.id.calendar).startAnimation(slide);
    	
    	mHelper.previousMonth();
    	initCells();
    	invalidate();
    }
    public boolean isLastMonth(Cell c){
    	return(!c.actualMonth && c.getDayOfMonth()>15);
    }
    public boolean isNextMonth(Cell c){
    	return(!c.actualMonth && c.getDayOfMonth()<15);
    }
    public boolean firstDay(int day) {
    	return day==1;
    }
    
    public boolean lastDay(int day) {
    	return mHelper.getNumberOfDaysInMonth()==day;
    }
    
    public void goToday() {
    	Calendar cal = Calendar.getInstance();
    	mHelper = new MonthDisplayHelper(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH));
    	initCells();
    	invalidate();
    }
    
    public Calendar getDate() {
    	return mRightNow;
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {   		
	    	gestureDetector.onTouchEvent(event);
	    	 return true;
    }
  
    public void setOnCellTouchListener(OnCellTouchListener p) {
		mOnCellTouchListener = p;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// draw background
		super.onDraw(canvas);
		
		//draw week title
		mWeekTitle.draw(canvas);	
		
		// draw cells
		for(Cell[] week : mCells) {
			for(Cell day : week) {
				day.draw(canvas);
			}
		}
		
		 // draw today
		if(mDecoration!=null && mToday!=null) {
			//mDecoration.draw(canvas);
		}
		
				
	}
	
	public void testeSetDate(int day, Cell cell) {
		initCells();
    	invalidate();
		
	}

	public void setBusyDays(HashMap<Date, Integer> ocupados) {
		busyDays=ocupados;
	}
	
	/****c* Calendar/GrayCell
	 * DESCRIPTION
	 * Classe responsável pela auxilio no desenho das celulas do calendário
	 *
	 ****
	 */
	private class GrayCell extends Cell {
		public GrayCell(int dayOfMon, Rect rect, float s, Context context, HashMap<Date, Integer> busy, int m, int y, boolean isToday) {
			super(dayOfMon, rect, s, context, busy, m, y,isToday);
			super.actualMonth=false;
			mPaint.setColor(Color.GRAY);
		}			
	}
	
	/****c* Calendar/RedCell
	 * DESCRIPTION
	 * Classe responsável pela auxilio no desenho das celulas do calendário
	 *
	 ****
	 */
	private class RedCell extends Cell {
		public RedCell(int dayOfMon, Rect rect, float s, Context context, HashMap<Date, Integer> busy, int m, int y, boolean isToday) {
			super(dayOfMon, rect, s, context, busy, m, y, isToday);
			super.actualMonth=true;
			mPaint.setColor(Color.WHITE);
			this.weekend = true;
		}			
		
	}


	/****c* Calendar/MyGestureDetector
	 * DESCRIPTION
	 * Classe responsável pelos gestos no ecrâ
	 *
	 ****
	 */
	class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
		private static final int SWIPE_MIN_DISTANCE = 5;
	    private static final int SWIPE_MAX_OFF_PATH = 250;
	    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
	    
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        	try {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return true;
                if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                	nextMonth();
                	mOnCellTouchListener.onTouch(null);
                	swipedNext=true;
                	
    		       
                }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                	previousMonth();
                	mOnCellTouchListener.onTouch(null);
                	swipePrev=true;
                }
            } catch (Exception e) {
                // nothing
            }
            return true;
        }
        @Override
    	public boolean onDown(MotionEvent e) {
        	//Log.d(TAG, "onlydown");
    		// TODO Auto-generated method stub
    		
    		return false;
    	}

    	@Override
    	public void onLongPress(MotionEvent e) {
    		//Log.d(TAG, "long press");
    		// TODO Auto-generated method stub
    		
    	}

    	@Override
    	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
    			float distanceY) {
    		//Log.d(TAG, "scroll");
    		// TODO Auto-generated method stub
    		return false;
    	}

    	@Override
    	public void onShowPress(MotionEvent e) {
    		//Log.d(TAG, "showpress");
    		// TODO Auto-generated method stub
    		
    	}

    	@Override
    	public boolean onSingleTapUp(MotionEvent event) {
    		//Log.d(TAG, "downup");
    		if(mOnCellTouchListener!=null){
        		for(Cell[] week : mCells) {
    				for(Cell day : week) {
    					if(day.hitTest((int)event.getX(), (int)event.getY())) {
    						mOnCellTouchListener.onTouch(day);
    					}						
    				}
    			}
    		}
    		return false;
    	}
    }

	
}
